package com.ddxz.middleground.master.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ddxz.middleground.master.dto.MasterHeader;
import com.ddxz.middleground.master.dto.user.*;
import com.ddxz.middleground.master.entity.UserEntity;
import com.ddxz.middleground.master.mapper.UserMapper;
import com.ddxz.middleground.master.mapper.UserRoleMapper;
import com.ddxz.middleground.master.service.RoleService;
import com.ddxz.middleground.master.service.UserService;
import com.ddxz.tool.core.common.CommonUtil;
import com.ddxz.tool.core.common.DdxzJwtUtil;
import com.ddxz.tool.core.convert.*;
import com.ddxz.tool.core.security.SecurityUtil;
import com.ddxz.tool.web.dto.DdxzException;
import com.ddxz.tool.web.dto.DdxzResponse;
import com.ddxz.tool.web.dto.PageResponse;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static com.ddxz.middleground.master.util.ErrorStatus.*;

/**
 * class description
 *
 * @author 朱宗刚
 * @version 1.0.0
 * @date 2020/7/28
 */

@Service
public class UserServiceImpl implements UserService {
    @Override
    public DdxzResponse getUserList(MasterHeader header, UserPage pageParam) {
        PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize());
        Page<UserEntity> userList = userMapper.getUserByDeptId(pageParam.getDeptId(), header.getTenant(), pageParam.getKeyword());
        return DdxzResponse.correct(PageResponse.getInstance(userList, User.class, DdxzUtil.SECOND_DATE));
    }

    @Override
    public DdxzResponse getUserDetail(MasterHeader header, String userId) {
        UserEntity entity = userMapper.getUserById(userId, header.getTenant());
        CommonUtil.ddxzAssetNull(entity, USER_NOT_EXISTS);
        return DdxzResponse.correct(BeanUtil.getTarget(entity, UserDetail.class, DdxzUtil.SECOND_DATETIME));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DdxzResponse saveUser(UserInfo user, MasterHeader header) {
        checkUser(user);
        UserEntity entity = new UserEntity();
        BeanUtil.copyProperties(user, entity);
        if (StringUtil.isEmpty(user.getId())) {
            // 新增用户，检查登录名是否重复
            Integer num = userMapper.getNumByName(user.getUsername(), header.getTenant());
            CommonUtil.ddxzAssetGreat(num, 0, LOGIN_NAME_REPEAT);
            entity.setId(CommonUtil.generatorId(T_USER));
            entity.setUserId(header.getUserId());
            entity.setPassword(SecurityUtil.md5(user.getUsername() + DEFAULT_PASSWORD));
            entity.setUsername(header.getNickname());
            entity.setExpiredTime(DateUtil.getCurrentTime() + passwordExpired);
            userMapper.saveUser(entity, header.getTenant());
        } else {
            // 更新用户信息，直接修改即可
            userMapper.modifyUser(entity, header.getTenant());
        }

        return DdxzResponse.correct(entity.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DdxzResponse changePassword(ChangePassword changePassword, MasterHeader header) {
        UserEntity user = userMapper.getUserById(header.getUserId(), header.getTenant());
        CommonUtil.ddxzAssetNull(user, USER_NOT_EXISTS);
        if (SecurityUtil.md5(user.getUsername() + changePassword.getOldPassword()).equals(user.getPassword())) {
            user.setPassword(SecurityUtil.md5(user.getUsername() + changePassword.getNewPassword()));
            user.setExpiredTime(DateUtil.getCurrentTime() + passwordExpired);
            user.setState(NORMAL);
            userMapper.changePassword(user, header.getTenant());
            return DdxzResponse.correct(OK_MESSAGE);
        }

        return DdxzResponse.error(ERROR_PASSWORD);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DdxzResponse resetPassword(String userId, MasterHeader header) {
        UserEntity entity = userMapper.getUserById(userId, header.getTenant());
        CommonUtil.ddxzAssetNull(entity, USER_NOT_EXISTS);
        entity.setPassword(SecurityUtil.md5(entity.getUsername() + DEFAULT_PASSWORD));
        entity.setExpiredTime(DateUtil.getCurrentTime() + passwordExpired);
        entity.setState(FIRST);
        userMapper.changePassword(entity, header.getTenant());
        return DdxzResponse.correct("密码重置成功", OK_MESSAGE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DdxzResponse removeUser(String userId, MasterHeader header) {
        userMapper.removeUser(userId, header.getTenant());
        userRoleMapper.removeByUserId(userId, header.getTenant());
        return DdxzResponse.correct(OK_MESSAGE);
    }

    @Override
    public DdxzResponse login(UserLogin login) {
        String username = SecurityUtil.rsaDecode(login.getUsername());
        String password = SecurityUtil.rsaDecode(login.getPassword());
        UserEntity entity = userMapper.getUserByName(username, login.getTenant());
        CommonUtil.ddxzAssetNull(entity, USER_NOT_EXISTS);
        if (!entity.getPassword().equals(SecurityUtil.md5(username + password))) {
            return DdxzResponse.error(PASSWORD_ERROR);
        }

        MasterHeader header = new MasterHeader();
        header.setTenant(login.getTenant());
        header.setUserId(entity.getId());
        header.setNickname(entity.getNickname());
        header.setDeptId(entity.getDeptId());
        List<String> roleIds = userRoleMapper.getRoleIdByUserId(entity.getId(), login.getTenant());
        header.setRoleIds(StringUtil.join(roleIds));
        roleIds.forEach(roleId ->
            roleService.getMenuByRoleId(roleId, login.getTenant()).forEach(menuId ->
                    redisTemplate.opsForSet().add(roleId, menuId))
        );
        return DdxzResponse.correct(jwtUtil.getToken((JSONObject) JSONObject.toJSON(header), tokenExpired));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DdxzResponse grantUser(MasterHeader header, String userId, List<String> roleIds) {
        if(CollectionUtil.isEmpty(roleIds)) {
            userRoleMapper.removeByUserId(userId, header.getTenant());
            return DdxzResponse.correct("授权成功", OK_MESSAGE);
        }

        userRoleMapper.removeUserRole(userId, roleIds, header.getTenant());
        userRoleMapper.bindUserRole(userId, roleIds, header.getTenant());

        return DdxzResponse.correct("授权成功", OK_MESSAGE);
    }

    private void checkUser(UserInfo user) {
        checkGender(user.getGender());
        checkStatus(user.getStatus());

        if (user.getEducation() < BOTTOM_EDU || user.getEducation() > TOP_EDU) {
            throw new DdxzException(INVALID_EDUCATION);
        }
    }

    private final UserMapper userMapper;

    private final UserRoleMapper userRoleMapper;

    private final RoleService roleService;

    private final DdxzJwtUtil jwtUtil = new DdxzJwtUtil();

    private final RedisTemplate<String, Object> redisTemplate;

    public UserServiceImpl(UserMapper userMapper, UserRoleMapper userRoleMapper,
                           RoleService roleService, RedisTemplate<String, Object> redisTemplate) {
        this.userMapper = userMapper;
        this.userRoleMapper = userRoleMapper;
        this.roleService = roleService;
        this.redisTemplate = redisTemplate;
    }

    private Long passwordExpired;

    private Long tokenExpired;

    @Value("${ddxz.password.expired}")
    public void setPasswordExpired(String passwordExpired) {
        this.passwordExpired = Long.decode(passwordExpired) * DateUtil.SECOND_PER_DAY;
    }

    @Value("${ddxz.token.expired}")
    public void setTokenExpired(String tokenExpired) {
        this.tokenExpired = StringUtil.toLong(tokenExpired);
    }
}
